﻿Imports System.Net.Sockets
Imports System
Imports System.Text
Imports System.Threading
Imports Microsoft.VisualBasic
Imports System.Net
Imports System.ComponentModel
Imports System.IO
Imports System.Xml.Serialization

Public Class WorldClient
    'This better work...
#Region "Definitions"

    'Set this to false to disable debug output.
    Public Shared DEBUG_ENABLED As Boolean = True
    Public outputfont As Font
    Public outputfgcol As Color
    Public outputbgcol As Color
    Private SyncObject As ISynchronizeInvoke
    Private Runner As Thread
    Public ConnectionRunner As BackgroundWorker
    Public ConstructionRunner As BackgroundWorker
    Public StreamRunner As BackgroundWorker
    Public mudinfo As New Dictionary(Of String, String)
    Public WorldSocket As TcpClient = Nothing
    Public WorldStream As NetworkStream = Nothing
    Public Const buffersize As Integer = 65535
    Public readbuffer(buffersize) As Byte
    Public writebuffer(buffersize) As Byte
    Public WithEvents worldoutput As System.Windows.Forms.RichTextBox
    Public WithEvents worldinput As System.Windows.Forms.RichTextBox
    Public WithEvents worldcontainer As System.Windows.Forms.SplitContainer
    Public WithEvents inputcontainer As System.Windows.Forms.SplitContainer
    Public WithEvents worldtab As System.Windows.Forms.TabPage
    Public hostname As String
    Public portnumber As Int16
    Public worldname As String
    Public dataready As Boolean
    Public STATE_NORMAL = 1
    Public STATE_IAC = 2
    Public STATE_IAC_SB = 3
    Public STATE_CSI = 4
    Public BSMState As Int16
    Public useUTF8 As Boolean
    Public ECHO_NORMAL = 1
    Public ECHO_WARNING = 2
    Public ECHO_CRITICAL = 3
    Public ECHO_USER = 4
    Public ECHO_DEBUG = 5
    Public ANSI_BRIGHTSTATE As Boolean = False

#Region "IAC bytes"
    Public IAC_COMMAND = CByte(255)
    Public IAC_DO = CByte(253)
    Public IAC_DONT = CByte(254)
    Public IAC_WILL = CByte(251)
    Public IAC_WONT = CByte(252)
    Public IAC_SB = CByte(250)
    Public IAC_GA = CByte(249)
    Public IAC_ERASELINE = CByte(248)
    Public IAC_ERASECHAR = CByte(247)
    Public IAC_AYT = CByte(246)
    Public IAC_ABORT = CByte(245)
    Public IAC_INTERRUPT = CByte(244)
    Public IAC_BREAK = CByte(243)
    Public IAC_DATA = CByte(242)
    Public IAC_NOP = CByte(241)
    Public IAC_SE = CByte(240)
    Public IAC_ECHO = CByte(1)
    Public IAC_SGA = CByte(3)
    Public IAC_STATUS = CByte(5)
    Public IAC_TMRK = CByte(6)
    Public IAC_TERM = CByte(24)
    Public IAC_EOR = CByte(25)
    Public IAC_NAWS = CByte(31)
    Public IAC_TSPEED = CByte(32)
    Public IAC_FLOW = CByte(33)
    Public IAC_LINE = CByte(34)
    Public IAC_XDISP = CByte(35)
    Public IAC_ENV = CByte(36)
    Public IAC_NEWENV = CByte(39)
    Public IAC_CHARSET = CByte(42)
    Public IAC_STARTTLS = CByte(46)
    Public IAC_MSSP = CByte(70)
    Public IAC_MCP = CByte(86)
    Public IAC_MSP = CByte(90)
    Public IAC_MXP = CByte(91)
    Public IAC_IYFL = CByte(92)

#End Region
#Region "CSI bytes"
    Public CSI_CUU = CByte(65)
    Public CSI_CUD = CByte(66)
    Public CSI_CUF = CByte(67)
    Public CSI_CUB = CByte(68)
    Public CSI_CNL = CByte(69)
    Public CSI_CPL = CByte(70)
    Public CSI_CHA = CByte(71)
    Public CSI_CUP = CByte(72)
    Public CSI_ED = CByte(73)
    Public CSI_EL = CByte(74)
    Public CSI_SU = CByte(75)
    Public CSI_SD = CByte(76)
    Public CSI_HVP = CByte(102)
    Public CSI_SGR = CByte(109)
#End Region
#Region "ANSI bytes"
    Public ANSI_RESET = 0
    Public ANSI_BRIGHT = 1
    Public ANSI_FAINT = 2
    Public ANSI_ITALIC = 3
    Public ANSI_UNDERLINE = 4
    Public ANSI_BLINKSLOW = 5
    Public ANSI_BLINKRAPID = 6
    Public ANSI_INVERSE = 7
    Public ANSI_CONCEAL = 8
    Public ANSI_CROSSOUT = 9
    Public ANSI_PRIMARY = 10
    Public ANSI_BOLDOFF = 21
    Public ANSI_NORMAL = 22
    Public ANSI_BLINKOFF = 25
    Public ANSI_REVEAL = 28
    Public ANSI_BLACK = 30
    Public ANSI_RED = 31
    Public ANSI_GREEN = 32
    Public ANSI_YELLOW = 33
    Public ANSI_BLUE = 34
    Public ANSI_MAGENTA = 35
    Public ANSI_CYAN = 36
    Public ANSI_WHITE = 37
    Public ANSI_256COL = 38
    Public ANSI_DEFAULTBG = 39
    Public ANSI_BGBLACK = 40
    Public ANSI_BGRED = 41
    Public ANSI_BGGREEN = 42
    Public ANSI_BGYELLOW = 43
    Public ANSI_BGBLUE = 44
    Public ANSI_BGMAGENTA = 45
    Public ANSI_BGCYAN = 46
    Public ANSI_BGWHITE = 47
    Public ANSI_256COLBG = 48
#End Region
#Region "Delegates"
    Public Delegate Sub delupdateoutput(ByVal buffer() As Byte)
    Public Delegate Sub delechooutput(ByVal message As String, ByVal type As Int16)
    Public Delegate Sub delDoOutput(ByVal message As String)
    Public Delegate Sub delSetFGColor(ByVal color As Color)
    Public Delegate Sub delSetBGColor(ByVal color As Color)
    Public Delegate Sub delGetFGColor()
    Public Delegate Sub delGetFont()
    Public Delegate Sub delSetFont(ByVal font As Font)
    Public Delegate Sub ControlDelegate()
#End Region
#Region "Events"
    Public ConnectDone As New ManualResetEvent(False)
    Public SendDone As New ManualResetEvent(False)
    Public ReceiveDone As New ManualResetEvent(False)
    Public ConstructDone As New ManualResetEvent(False)
    Public DisconnectDone As New ManualResetEvent(False)
#End Region
    

#End Region
#Region "Interface"

    Public Sub containersize_change(ByVal sender As Object, ByVal e As System.Windows.Forms.SplitterEventArgs) Handles worldcontainer.SplitterMoved
        EchoOutput("I got a new splitterplacement for worldcontainer, " + CStr(worldcontainer.SplitterDistance), ECHO_DEBUG)
    End Sub
    Private Sub InputBox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles worldinput.KeyPress
        If (e.KeyChar = vbCr) Then
            worldinput.Focus()
            worldinput.SelectionStart = worldinput.TextLength - 1
            sendmessage(worldinput.Text)
            worldinput.Clear()
        End If
    End Sub
    Public Sub New()

        outputbgcol = Color.Black
        outputfgcol = Color.Silver
        outputfont = New Font("consolas", 11)


    End Sub
    Public Sub SetupWorld(ByVal newworldname As String, ByVal newhostname As String, ByVal newport As Int16)
        Me.worldname = newworldname
        Me.hostname = newhostname
        Me.portnumber = newport
        MainForm.SuspendLayout()
        ConstructDone.Reset()
        ConstructTab()
        ConstructDone.WaitOne()
        MainForm.Worlds.Add(Me, newworldname)
        EchoOutput("World setup completed.", ECHO_DEBUG)
        MainForm.ResumeLayout()
        DoConnect(hostname, portnumber)

    End Sub
    Public Sub EchoOutput(ByVal message As String, ByVal type As Int16)
        Dim curcolor As Color
        Dim newcolor As Color
        curcolor = outputfgcol
        'newcolor = Color.Pink
        'If worldoutput.InvokeRequired Then
        ' curcolor = worldoutput.Invoke(New delGetFGColor(AddressOf GetFgcolor))
        ' Else
        '
        '        curcolor = worldoutput.SelectionColor
        '        End If

        Select Case type
            Case ECHO_NORMAL
                newcolor = Color.Green
            Case ECHO_WARNING
                newcolor = Color.Yellow
            Case ECHO_CRITICAL
                newcolor = Color.OrangeRed
            Case ECHO_USER
                newcolor = Color.Green
            Case ECHO_DEBUG
                newcolor = Color.Red
            Case Else
                newcolor = Color.Pink
        End Select
        If (type = ECHO_DEBUG And DEBUG_ENABLED = False) Then
            'Silently drop output, we're not in debug mode.
        Else
            If worldoutput.InvokeRequired = True Then
                worldoutput.Invoke(New delSetFGColor(AddressOf SetFGColor), newcolor)
                'worldoutput.Invoke(New delDoOutput(AddressOf DoOutput), "Set color to " + newcolor.ToString)
                outputfgcol = newcolor
                worldoutput.Invoke(New delDoOutput(AddressOf DoOutput), message + vbCrLf)
                worldoutput.Invoke(New delSetFGColor(AddressOf SetFGColor), curcolor)
                outputfgcol = curcolor
            Else
                worldoutput.SelectionColor = newcolor
                worldoutput.AppendText(message + vbCrLf)
                worldoutput.SelectionColor = curcolor
            End If
            'If worldoutput.InvokeRequired = True Then
            'worldoutput.Invoke(New delSetFGColor(AddressOf SetFGColor), newcolor)
            'worldoutput.Invoke(New delDoOutput(AddressOf DoOutput), message)
            'worldoutput.Invoke(New delSetFGColor(AddressOf SetFGColor), curcolor)
            'End If
            'worldoutput.InvokeIfNecessary(Function() InlineAssignHelper(worldoutput.SelectionColor, newcolor))
            'worldoutput.InvokeIfNecessary(Function() InlineAssignHelper(worldoutput.Text, worldoutput.Text + message + vbCrLf))
            'worldoutput.InvokeIfNecessary(Function() InlineAssignHelper(worldoutput.SelectionColor, curcolor))


        End If
    End Sub
    Public Function GetFgcolor()
        Return Color.Pink

    End Function
    Public Function GetFont()
        Return worldoutput.SelectionFont

    End Function
    Public Sub SetFont(ByVal font As Font)
        worldoutput.SelectionFont = font
    End Sub
    Public Sub SetFGColor(ByVal color As Color)
        If worldoutput.InvokeRequired = True Then
            dolog("I have to invoke!")
        End If
        worldoutput.SelectionColor = color

    End Sub
    Public Sub SetBGColor(ByVal color As Color)
        worldoutput.SelectionBackColor = color
    End Sub
    Public Sub DoOutput(ByVal message As String)
        If outputfgcol = Color.Empty Then
            dolog("Empty color!")
            outputfgcol = Color.Silver
        End If
        worldoutput.SuspendLayout()
        worldoutput.Font = outputfont
        worldoutput.SelectionColor = outputfgcol
        worldoutput.SelectionBackColor = outputbgcol
        worldoutput.AppendText(message)
        worldoutput.ScrollToCaret()
        worldoutput.ResumeLayout()
    End Sub
    Public Sub ConstructTab()
        'Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Dim newworld As New WorldClient
        worldoutput = New System.Windows.Forms.RichTextBox
        newworld.worldtab = New System.Windows.Forms.TabPage
        newworld.worldtab.Name = worldname
        newworld.worldtab.Text = CStr(worldname)
        newworld.worldtab.SuspendLayout()
        MainForm.TabControl1.Controls.Add(newworld.worldtab)
        MainForm.TabControl1.SelectTab(newworld.worldtab)
        Dim currenttab As Control

        worldoutput.Dock = DockStyle.Fill
        worldoutput.ForeColor = Color.Silver
        worldoutput.BackColor = Color.Black

        currenttab = MainForm.TabControl1.SelectedTab
        worldcontainer = New System.Windows.Forms.SplitContainer
        worldcontainer.Orientation = Orientation.Horizontal
        worldcontainer.Dock = DockStyle.Fill
        worldcontainer.BorderStyle = BorderStyle.Fixed3D
        worldcontainer.BackColor = Color.Black
        worldcontainer.ForeColor = Color.Silver

        inputcontainer = New System.Windows.Forms.SplitContainer
        currenttab.Controls.Add(worldcontainer)
        worldcontainer.Panel2.Controls.Add(inputcontainer)
        inputcontainer.Orientation = Orientation.Vertical
        inputcontainer.BorderStyle = BorderStyle.Fixed3D
        inputcontainer.Dock = DockStyle.Fill
        inputcontainer.BackColor = Color.Black
        inputcontainer.ForeColor = Color.White

        worldcontainer.Panel1.Controls.Add(worldoutput)
        worldoutput.SelectionColor = Color.Blue
        worldoutput.SelectionColor = Color.Silver
        worldinput = New System.Windows.Forms.RichTextBox
        worldinput.Dock = DockStyle.Fill
        worldinput.ForeColor = Color.Silver
        worldinput.BackColor = Color.Black
        worldinput.Font = New System.Drawing.Font("consolas", 11)
        worldinput.Multiline = True
        worldoutput.Font = New System.Drawing.Font("consolas", 11)

        inputcontainer.Panel1.Controls.Add(worldinput)

        worldcontainer.Show()
        inputcontainer.Show()
        worldoutput.Show()
        worldinput.Show()
        newworld.worldtab.ResumeLayout()
        AddHandler newworld.worldtab.GotFocus, AddressOf TabChanged
        MainForm.ResumeLayout()
        worldcontainer.SplitterDistance = 670
        inputcontainer.SplitterDistance = 1400
        inputcontainer.Focus()
        worldinput.Focus()
        ConstructDone.Set()
    End Sub
    Public Sub TabChanged()
        Me.worldinput.Focus()
    End Sub
    Public Sub tab_selected(ByVal sender As Object, ByVal e As System.EventArgs) Handles worldtab.Click
        worldinput.Focus()
    End Sub
    Public Sub dolog(ByVal message As String)
        Dim OutputWriter As New delechooutput(AddressOf EchoOutput)
        OutputWriter.Invoke(message, ECHO_DEBUG)
    End Sub

#End Region
    Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
        target = value
        Return value
    End Function
#Region "TCPConnection"
    Public Sub DoReconnect()
        If WorldSocket.Connected Then
            EchoOutput("Already connected.", ECHO_WARNING)
        Else
            EchoOutput("Reconnecting to " + worldname + "...", ECHO_NORMAL)

            DoConnect(hostname, portnumber)
        End If

    End Sub
    Public Sub DoDisconnect()
        If WorldSocket.Connected Then
            EchoOutput("Closing connection.", ECHO_NORMAL)
            WorldStream.Close()
            WorldSocket.Close()

        End If
    End Sub
    Public Sub DoConnect(ByVal host As String, ByVal port As Int16)
        'Connect to the world.
        EchoOutput("Looking up host " + host, ECHO_NORMAL)
        Dim ipHostInfo As IPHostEntry
        Dim ipaddress As IPAddress
        Try
            ipHostInfo = Dns.GetHostEntry(host)
            ipaddress = ipHostInfo.AddressList(0)
            'Lets find out if we are going to connect to an IPv6 host or not...
            If (ipaddress.AddressFamily = AddressFamily.InterNetworkV6) Then
                WorldSocket = New TcpClient(AddressFamily.InterNetworkV6)
            Else
                WorldSocket = New TcpClient(AddressFamily.InterNetwork)
            End If
            Try
                EchoOutput("Connecting to " + ipaddress.ToString + " port " + CStr(port) + "...", ECHO_NORMAL)
                ConnectDone.Reset()
                WorldSocket.BeginConnect(host, port, New AsyncCallback(AddressOf ConnectComplete), WorldSocket)
                ' Wait for our socket to connect before setting up the buffers.
                ConnectDone.WaitOne()
                If WorldSocket.Connected Then
                    EchoOutput("Connection established.", ECHO_NORMAL)
                    'WorldSocket.Connect(host, port)
                    WorldStream = WorldSocket.GetStream
                    WorldStream.BeginRead(readbuffer, 0, readbuffer.Length, New AsyncCallback(AddressOf DataReceived), WorldStream)
                Else
                    EchoOutput("We didn't get a socket. :(", ECHO_CRITICAL)
                End If


            Catch ex As Exception
                MsgBox("Error:" + ex.ToString())
                EchoOutput("Error connecting: " + ex.ToString(), ECHO_CRITICAL)

            End Try
        Catch ex As Exception
            MsgBox("Error:" + ex.ToString())
            EchoOutput("Couldn't connect: " + ex.ToString(), ECHO_CRITICAL)
        End Try



    End Sub
    Private Sub DataReceived(ByVal p1 As System.IAsyncResult)
        Dim totalread As Integer
        Dim outputbuffer(buffersize) As Byte
        Dim OutputWriter As delupdateoutput
        EchoOutput("In Datareceived.", ECHO_DEBUG)
        Try
            If WorldStream.CanRead Then
                totalread = WorldSocket.GetStream.EndRead(p1)
            Else
                EchoOutput("Can't read from world stream!", ECHO_CRITICAL)
            End If

        Catch ex As Exception
            MessageBox.Show(ex.ToString)


        End Try
        If totalread > 0 Then
            outputbuffer = readbuffer
            ReDim Preserve outputbuffer(totalread)
        End If

        Try

            OutputWriter = New delupdateoutput(AddressOf updateoutput)
            OutputWriter.Invoke(outputbuffer)
            WorldSocket.GetStream.BeginRead(readbuffer, 0, readbuffer.Length, New AsyncCallback(AddressOf DataReceived), WorldStream)

        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        End Try

    End Sub
    Public Sub ConnectComplete(ByVal ar As System.IAsyncResult)

        Try
            WorldSocket.EndConnect(ar)
        Catch ex As Exception
            'Blatantly ignared!
        End Try

        ConnectDone.Set()
    End Sub
    Private Sub sendmessage(ByVal msg As String)
        'Try
        '    If (useUTF8 = True) Then
        '        writebuffer = System.Text.Encoding.UTF8.GetBytes(msg)
        '    Else
        '        writebuffer = System.Text.Encoding.ASCII.GetBytes(msg)
        '    End If
        'Catch ex As Exception
        '    MessageBox.Show(ex.ToString)
        'End Try
        'dolog("Sent some text.")
        Dim bytes As [Byte]()
        If useUTF8 = True Then
            bytes = Encoding.UTF8.GetBytes(msg)
        Else
            bytes = Encoding.ASCII.GetBytes(msg)
        End If

        WorldStream.Write(bytes, 0, bytes.Length)
    End Sub
    Public Sub FlushBuffer(ByVal buffer() As Byte)
        If useUTF8 = True Then
            If worldoutput.InvokeRequired = True Then
                worldoutput.Invoke(New delDoOutput(AddressOf DoOutput), System.Text.Encoding.UTF8.GetString(buffer))

            Else

                worldoutput.AppendText(System.Text.Encoding.UTF8.GetString(buffer))
            End If

        Else
            If worldoutput.InvokeRequired = True Then
                worldoutput.Invoke(New delDoOutput(AddressOf DoOutput), System.Text.Encoding.UTF8.GetString(buffer))

            Else

                worldoutput.AppendText(System.Text.Encoding.Default.GetString(buffer))
            End If
        End If

    End Sub
    Public Sub updateoutput(ByVal buffer() As Byte)
        'New sub for updating output, now with sane passing of buffers.
        dolog("Got a " + CStr(UBound(buffer)) + " byte buffer")
        If (UBound(buffer) < 1) Then
            dolog("Buffer is null characters, ending processing.")
            Exit Sub
        End If
        worldoutput.SuspendLayout()
        MainForm.SuspendLayout()
        Dim bLength As Long
        Dim outputbuffer(UBound(buffer)) As Byte
        Dim i As Long
        Dim j As Long
        Dim tempbuffer() As Byte = {}
        bLength = UBound(buffer)
        For i = 0 To bLength - 1
            If (buffer(i) = CByte(255)) Then
                'We've received a Telnet IAC, flush our buffer and pass the rest to IAC handling.
                FlushBuffer(outputbuffer)
                'Actually, let's do a bit more here. Check and see if we have an IAC SB.
                If (buffer(i + 1) = IAC_SB) Then
                    dolog("Have an IAC SB in updateoutput")
                    ReDim tempbuffer((UBound(buffer) - i))
                    For j = i To bLength - 1
                        If (buffer(j) = IAC_SE) Then
                            dolog("Found IAC SE in updateoutput, passing to TelnetIAC")
                            tempbuffer(j - i) = buffer(j)
                            TelnetIAC(tempbuffer, i)
                            ReDim tempbuffer((UBound(buffer) - i))
                            For k = j To bLength - 1
                                tempbuffer(k - j) = buffer(k)
                            Next
                            updateoutput(tempbuffer)
                            Exit Sub

                        Else
                            tempbuffer(j - i) = buffer(j)
                        End If

                    Next
                ElseIf (buffer(i + 1) = IAC_COMMAND) Then
                    dolog("Have a literal 255 byte")
                    i = i + 1
                Else
                    dolog("Have an IAC three byte command. Pass it to handler, advance counter and resend to updateoutput.")
                    TelnetIAC({buffer(i), buffer(i + 1), buffer(i + 2)}, 0)
                    i = i + 3
                    ReDim tempbuffer((UBound(buffer) - i))
                    For j = i To bLength - 1
                        tempbuffer(j - i) = buffer(j)
                    Next
                    updateoutput(tempbuffer)
                    Exit Sub
                End If
            ElseIf (buffer(i) = CByte(27)) Then
                'We've received an escape character, check to see if it's a CSi sequence.
                If (buffer(i + 1) = CByte(91)) Then
                    'It's a CSI sequence, pop our buffer to the CSI handler.
                    dolog("Flushing a " + CStr(outputbuffer.Length) + " byte buffer before CSI processing.")
                    FlushBuffer(outputbuffer)
                    processCSI(buffer, i)
                    Exit Sub
                End If
            Else
                'Looks like a normal printable character, pass it to the output buffer.
                outputbuffer(i) = buffer(i)

            End If
        Next
        'We've reached the end of our available bytes, flush the output buffer.
        dolog("Flushing a " + CStr(outputbuffer.Length) + " byte buffer")
        MainForm.ResumeLayout()
        worldoutput.ResumeLayout()
        FlushBuffer(outputbuffer)

    End Sub
#End Region
#Region "ANSI"
    Public Sub processCSI(ByVal buffer() As Byte, ByVal startpoint As Long)
        Dim bLength As Long = UBound(buffer)
        Dim tempbuffer() As Byte = {}
        Dim tempstr As String = ""
        'dolog("Processing CSI")
        For j = startpoint To bLength - 1

            Select Case buffer(j)
                Case CSI_CUU
                    'Unimplemented
                Case CSI_CUD
                Case CSI_CUF
                Case CSI_CUB
                Case CSI_CNL
                Case CSI_CPL
                Case CSI_CHA
                Case CSI_CUP
                Case CSI_ED
                Case CSI_EL
                Case CSI_SU
                Case CSI_SD
                Case CSI_HVP
                    dolog("Unimplemented CSI escape code " + CStr(buffer(j)))

                Case CSI_SGR
                    'dolog("Parsing ANSI string. Tempbuffer is " + CStr(UBound(tempbuffer)) + " bytes")

                    For k = 0 To UBound(tempbuffer)
                        'dolog("Byte in buffer: " + CStr(tempbuffer(k)))
                        If (tempbuffer(k) = CByte(59)) Then
                            'dolog("Found a separator ;")
                            tempstr = tempstr + System.Text.Encoding.ASCII.GetString(tempbuffer, k, 1)
                        ElseIf (tempbuffer(k) = CByte(27)) Then
                            'dolog("Found escape character")
                        ElseIf (tempbuffer(k) = CByte(91)) Then
                            'dolog("Found CSI char")
                        ElseIf (tempbuffer(k) = CByte(109)) Then
                            'dolog("Found end of SGR sequence char.")
                            CSIAnsi(tempstr)
                        Else
                            tempstr = tempstr + System.Text.Encoding.ASCII.GetString(tempbuffer, k, 1)
                            'dolog("Tempstr push: " + tempstr)
                        End If
                    Next
                    'dolog("Done processing one CSI, pushing back to outputbuffer")
                    ReDim tempbuffer(UBound(buffer) - j)
                    For l = (j + 1) To (UBound(buffer) - 1)
                        tempbuffer((l - (j + 1))) = buffer(l)
                    Next
                    CSIAnsi(tempstr)
                    updateoutput(tempbuffer)
                    Exit Sub
                Case Else
                    'dolog("Pushed a byte to tempbuffer, " + CStr(buffer(j)))
                    ReDim Preserve tempbuffer(UBound(tempbuffer) + 1)
                    tempbuffer(UBound(tempbuffer)) = buffer(j)
            End Select
        Next
    End Sub
    Public Sub CSIAnsi(ByVal tempstr As String)
        dolog("CSIAnsi entered: " + tempstr)
        Dim currentFont As System.Drawing.Font
        Dim newFontStyle As System.Drawing.FontStyle
        Dim newfgcolor As Color = Color.Silver
        Dim newbgcolor As Color = Color.Black
        Dim command As String = ""
        Dim subcommand As String = ""
        Dim colorbyte As String = ""
        If worldoutput.InvokeRequired = True Then
            currentFont = worldoutput.Invoke(New delGetFont(AddressOf GetFont))
        Else
            currentFont = worldoutput.SelectionFont
        End If
        If (InStr(tempstr, ";")) Then
            command = tempstr.Substring(0, tempstr.IndexOf(";"))
            subcommand = tempstr.Substring(tempstr.IndexOf(";") + 1)
        End If
        If (command = "") Then
            command = tempstr
        End If
        'OK, so let's cheat.
        If (CInt(command) = ANSI_BRIGHT And subcommand.Length > 0) Then
            dolog("Cheating...")
            ANSI_BRIGHTSTATE = True
            command = CInt(subcommand)
        End If
        Select Case CInt(command)

            Case ANSI_RESET
                newfgcolor = Color.Silver
                newbgcolor = Color.Black
                newFontStyle = FontStyle.Regular
                ANSI_BRIGHTSTATE = False
            Case ANSI_BRIGHT
                ANSI_BRIGHTSTATE = True
                newfgcolor = Color.White
            Case ANSI_FAINT
                newfgcolor = Color.Gray
                ANSI_BRIGHTSTATE = False
            Case ANSI_ITALIC
                newFontStyle = FontStyle.Italic
            Case ANSI_UNDERLINE
                newFontStyle = FontStyle.Underline
            Case ANSI_BLINKSLOW
                'unimplemented
            Case ANSI_BLINKRAPID
                'unimplemented
            Case ANSI_INVERSE
                'Unimplemented
            Case ANSI_CONCEAL
            Case ANSI_CROSSOUT
            Case ANSI_PRIMARY
            Case ANSI_BOLDOFF
            Case ANSI_NORMAL
                'dolog("Set normal")
            Case ANSI_BLINKOFF
            Case ANSI_REVEAL
            Case ANSI_BLACK
                newfgcolor = Color.Black
                'dolog("set black")
            Case ANSI_RED
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.Red
                Else
                    newfgcolor = Color.DarkRed
                End If
            Case ANSI_GREEN
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.LimeGreen
                Else
                    newfgcolor = Color.Green
                End If
            Case ANSI_YELLOW
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.LightYellow
                Else
                    newfgcolor = Color.Yellow
                End If

            Case ANSI_BLUE
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.LightBlue
                Else
                    newfgcolor = Color.Blue
                End If
            Case ANSI_MAGENTA
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.Magenta
                Else
                    newfgcolor = Color.DarkMagenta
                End If

            Case ANSI_CYAN
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.LightCyan
                Else
                    newfgcolor = Color.Cyan
                End If

            Case ANSI_WHITE
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.White
                Else
                    newfgcolor = Color.AntiqueWhite
                End If
            Case ANSI_BGBLACK
                If (ANSI_BRIGHTSTATE = True) Then
                    newfgcolor = Color.Gray
                Else
                    newbgcolor = Color.Black
                End If

            Case ANSI_BGRED
                If (ANSI_BRIGHTSTATE = True) Then
                    newbgcolor = Color.Red
                Else
                    newbgcolor = Color.DarkRed
                End If
            Case ANSI_BGGREEN
                If (ANSI_BRIGHTSTATE = True) Then
                    newbgcolor = Color.LimeGreen
                Else
                    newbgcolor = Color.Green
                End If
            Case ANSI_BGYELLOW
                If (ANSI_BRIGHTSTATE = True) Then
                    newbgcolor = Color.LightYellow
                Else
                    newbgcolor = Color.Yellow
                End If
            Case ANSI_BGBLUE
                If (ANSI_BRIGHTSTATE = True) Then
                    newbgcolor = Color.LightBlue
                Else
                    newbgcolor = Color.Blue
                End If
            Case ANSI_BGMAGENTA
                If (ANSI_BRIGHTSTATE = True) Then
                    newbgcolor = Color.Magenta
                Else
                    newbgcolor = Color.DarkMagenta
                End If
            Case ANSI_BGCYAN
                If (ANSI_BRIGHTSTATE = True) Then
                    newbgcolor = Color.LightCyan
                Else
                    newbgcolor = Color.Cyan
                End If
            Case ANSI_BGWHITE
                If (ANSI_BRIGHTSTATE = True) Then
                    newbgcolor = Color.White
                Else
                    newbgcolor = Color.AntiqueWhite
                End If

            Case ANSI_256COL
                'dolog("In 256Color ANSI...")
                If (InStr(subcommand, ";")) Then
                    colorbyte = subcommand.Substring(subcommand.IndexOf(";") + 1)
                End If
                newfgcolor = Get256Col(colorbyte)
            Case ANSI_256COLBG
                If (InStr(subcommand, ";")) Then
                    colorbyte = subcommand.Substring(subcommand.IndexOf(";") + 1)
                End If
                dolog("Picking BGColor")
                newbgcolor = Get256Col(colorbyte)
            Case ANSI_DEFAULTBG
            Case Else
                dolog("Unknown CSI " + tempstr)
        End Select

        If worldoutput.InvokeRequired Then
            worldoutput.Invoke(New delSetFGColor(AddressOf SetFGColor), newfgcolor)
            worldoutput.Invoke(New delSetBGColor(AddressOf SetBGColor), newbgcolor)
            outputfgcol = newfgcolor
            outputbgcol = newbgcolor
        Else
            worldoutput.SelectionColor = newfgcolor
            worldoutput.SelectionBackColor = newbgcolor
            outputfgcol = newfgcolor
            outputbgcol = newbgcolor

        End If

    End Sub
    Public Function Get256Col(ByVal colorbyte As Int16) As Color
        dolog("Picking color value for cbyte " + CStr(colorbyte))
        Select Case colorbyte
            Case 16
                Return Color.FromArgb(255, 0, 0, 0)
            Case 17
                Return Color.FromArgb(255, 0, 0, 95)
            Case 18
                Return Color.FromArgb(255, 0, 0, 135)
            Case 19
                Return Color.FromArgb(255, 0, 0, 175)
            Case 20
                Return Color.FromArgb(255, 0, 0, 215)
            Case 21
                Return Color.FromArgb(255, 0, 0, 255)
            Case 22
                Return Color.FromArgb(255, 0, 95, 0)
            Case 23
                Return Color.FromArgb(255, 0, 95, 95)
            Case 24
                Return Color.FromArgb(255, 0, 95, 135)
            Case 25
                Return Color.FromArgb(255, 0, 95, 175)
            Case 26
                Return Color.FromArgb(255, 0, 95, 215)
            Case 27
                Return Color.FromArgb(255, 0, 95, 255)
            Case 28
                Return Color.FromArgb(255, 0, 135, 0)
            Case 29
                Return Color.FromArgb(255, 0, 135, 95)
            Case 30
                Return Color.FromArgb(255, 0, 135, 135)
            Case 31
                Return Color.FromArgb(255, 0, 135, 175)
            Case 32
                Return Color.FromArgb(255, 0, 135, 215)
            Case 33
                Return Color.FromArgb(255, 0, 135, 255)
            Case 34
                Return Color.FromArgb(255, 0, 175, 0)
            Case 35
                Return Color.FromArgb(255, 0, 175, 95)
            Case 36
                Return Color.FromArgb(255, 0, 175, 135)
            Case 37
                Return Color.FromArgb(255, 0, 175, 175)
            Case 38
                Return Color.FromArgb(255, 0, 175, 215)
            Case 39
                Return Color.FromArgb(255, 0, 175, 255)
            Case 40
                Return Color.FromArgb(255, 0, 215, 0)
            Case 41
                Return Color.FromArgb(255, 0, 215, 95)
            Case 42
                Return Color.FromArgb(255, 0, 215, 135)
            Case 43
                Return Color.FromArgb(255, 0, 215, 175)
            Case 44
                Return Color.FromArgb(255, 0, 215, 215)
            Case 45
                Return Color.FromArgb(255, 0, 215, 255)
            Case 46
                Return Color.FromArgb(255, 0, 255, 0)
            Case 47
                Return Color.FromArgb(255, 0, 255, 95)
            Case 48
                Return Color.FromArgb(255, 0, 255, 135)
            Case 49
                Return Color.FromArgb(255, 0, 255, 175)
            Case 50
                Return Color.FromArgb(255, 0, 255, 215)
            Case 51
                Return Color.FromArgb(255, 0, 255, 255)
            Case 52
                Return Color.FromArgb(255, 95, 0, 0)
            Case 53
                Return Color.FromArgb(255, 95, 0, 95)
            Case 54
                Return Color.FromArgb(255, 95, 0, 135)
            Case 55
                Return Color.FromArgb(255, 95, 0, 175)
            Case 56
                Return Color.FromArgb(255, 95, 0, 215)
            Case 57
                Return Color.FromArgb(255, 95, 0, 255)
            Case 58
                Return Color.FromArgb(255, 95, 95, 0)
            Case 59
                Return Color.FromArgb(255, 95, 95, 95)
            Case 60
                Return Color.FromArgb(255, 95, 95, 135)
            Case 61
                Return Color.FromArgb(255, 95, 95, 175)
            Case 62
                Return Color.FromArgb(255, 95, 95, 215)
            Case 63
                Return Color.FromArgb(255, 95, 95, 255)
            Case 64
                Return Color.FromArgb(255, 95, 135, 0)
            Case 65
                Return Color.FromArgb(255, 95, 135, 95)
            Case 66
                Return Color.FromArgb(255, 95, 135, 135)
            Case 67
                Return Color.FromArgb(255, 95, 135, 175)
            Case 68
                Return Color.FromArgb(255, 95, 135, 215)
            Case 69
                Return Color.FromArgb(255, 95, 135, 255)
            Case 70
                Return Color.FromArgb(255, 95, 175, 0)
            Case 71
                Return Color.FromArgb(255, 95, 175, 95)
            Case 72
                Return Color.FromArgb(255, 95, 175, 135)
            Case 73
                Return Color.FromArgb(255, 95, 175, 175)
            Case 74
                Return Color.FromArgb(255, 95, 175, 215)
            Case 75
                Return Color.FromArgb(255, 95, 175, 255)
            Case 76
                Return Color.FromArgb(255, 95, 215, 0)
            Case 77
                Return Color.FromArgb(255, 95, 215, 95)
            Case 78
                Return Color.FromArgb(255, 95, 215, 135)
            Case 79
                Return Color.FromArgb(255, 95, 215, 175)
            Case 80
                Return Color.FromArgb(255, 95, 215, 215)
            Case 81
                Return Color.FromArgb(255, 95, 215, 255)
            Case 82
                Return Color.FromArgb(255, 95, 255, 0)
            Case 83
                Return Color.FromArgb(255, 95, 255, 95)
            Case 84
                Return Color.FromArgb(255, 95, 255, 135)
            Case 85
                Return Color.FromArgb(255, 95, 255, 175)
            Case 86
                Return Color.FromArgb(255, 95, 255, 215)
            Case 87
                Return Color.FromArgb(255, 95, 255, 255)
            Case 88
                Return Color.FromArgb(255, 135, 0, 0)
            Case 89
                Return Color.FromArgb(255, 135, 0, 95)
            Case 90
                Return Color.FromArgb(255, 135, 0, 135)
            Case 91
                Return Color.FromArgb(255, 135, 0, 175)
            Case 92
                Return Color.FromArgb(255, 135, 0, 215)
            Case 93
                Return Color.FromArgb(255, 135, 0, 255)
            Case 94
                Return Color.FromArgb(255, 135, 95, 0)
            Case 95
                Return Color.FromArgb(255, 135, 95, 95)
            Case 96
                Return Color.FromArgb(255, 135, 95, 135)
            Case 97
                Return Color.FromArgb(255, 135, 95, 175)
            Case 98
                Return Color.FromArgb(255, 135, 95, 215)
            Case 99
                Return Color.FromArgb(255, 135, 95, 255)
            Case 100
                Return Color.FromArgb(255, 135, 135, 0)
            Case 101
                Return Color.FromArgb(255, 135, 135, 95)
            Case 102
                Return Color.FromArgb(255, 135, 135, 135)
            Case 103
                Return Color.FromArgb(255, 135, 135, 175)
            Case 104
                Return Color.FromArgb(255, 135, 135, 215)
            Case 105
                Return Color.FromArgb(255, 135, 135, 255)
            Case 106
                Return Color.FromArgb(255, 135, 175, 0)
            Case 107
                Return Color.FromArgb(255, 135, 175, 95)
            Case 108
                Return Color.FromArgb(255, 135, 175, 135)
            Case 109
                Return Color.FromArgb(255, 135, 175, 175)
            Case 110
                Return Color.FromArgb(255, 135, 175, 215)
            Case 111
                Return Color.FromArgb(255, 135, 175, 255)
            Case 112
                Return Color.FromArgb(255, 135, 215, 0)
            Case 113
                Return Color.FromArgb(255, 135, 215, 95)
            Case 114
                Return Color.FromArgb(255, 135, 215, 135)
            Case 115
                Return Color.FromArgb(255, 135, 215, 175)
            Case 116
                Return Color.FromArgb(255, 135, 215, 215)
            Case 117
                Return Color.FromArgb(255, 135, 215, 255)
            Case 118
                Return Color.FromArgb(255, 135, 255, 0)
            Case 119
                Return Color.FromArgb(255, 135, 255, 95)
            Case 120
                Return Color.FromArgb(255, 135, 255, 135)
            Case 121
                Return Color.FromArgb(255, 135, 255, 175)
            Case 122
                Return Color.FromArgb(255, 135, 255, 215)
            Case 123
                Return Color.FromArgb(255, 135, 255, 255)
            Case 124
                Return Color.FromArgb(255, 175, 0, 0)
            Case 125
                Return Color.FromArgb(255, 175, 0, 95)
            Case 126
                Return Color.FromArgb(255, 175, 0, 135)
            Case 127
                Return Color.FromArgb(255, 175, 0, 175)
            Case 128
                Return Color.FromArgb(255, 175, 0, 215)
            Case 129
                Return Color.FromArgb(255, 175, 0, 255)
            Case 130
                Return Color.FromArgb(255, 175, 95, 0)
            Case 131
                Return Color.FromArgb(255, 175, 95, 95)
            Case 132
                Return Color.FromArgb(255, 175, 95, 135)
            Case 133
                Return Color.FromArgb(255, 175, 95, 175)
            Case 134
                Return Color.FromArgb(255, 175, 95, 215)
            Case 135
                Return Color.FromArgb(255, 175, 95, 255)
            Case 136
                Return Color.FromArgb(255, 175, 135, 0)
            Case 137
                Return Color.FromArgb(255, 175, 135, 95)
            Case 138
                Return Color.FromArgb(255, 175, 135, 135)
            Case 139
                Return Color.FromArgb(255, 175, 135, 175)
            Case 140
                Return Color.FromArgb(255, 175, 135, 215)
            Case 141
                Return Color.FromArgb(255, 175, 135, 255)
            Case 142
                Return Color.FromArgb(255, 175, 175, 0)
            Case 143
                Return Color.FromArgb(255, 175, 175, 95)
            Case 144
                Return Color.FromArgb(255, 175, 175, 135)
            Case 145
                Return Color.FromArgb(255, 175, 175, 175)
            Case 146
                Return Color.FromArgb(255, 175, 175, 215)
            Case 147
                Return Color.FromArgb(255, 175, 175, 255)
            Case 148
                Return Color.FromArgb(255, 175, 215, 0)
            Case 149
                Return Color.FromArgb(255, 175, 215, 95)
            Case 150
                Return Color.FromArgb(255, 175, 215, 135)
            Case 151
                Return Color.FromArgb(255, 175, 215, 175)
            Case 152
                Return Color.FromArgb(255, 175, 215, 215)
            Case 153
                Return Color.FromArgb(255, 175, 215, 255)
            Case 154
                Return Color.FromArgb(255, 175, 255, 0)
            Case 155
                Return Color.FromArgb(255, 175, 255, 95)
            Case 156
                Return Color.FromArgb(255, 175, 255, 135)
            Case 157
                Return Color.FromArgb(255, 175, 255, 175)
            Case 158
                Return Color.FromArgb(255, 175, 255, 215)
            Case 159
                Return Color.FromArgb(255, 175, 255, 255)
            Case 160
                Return Color.FromArgb(255, 215, 0, 0)
            Case 161
                Return Color.FromArgb(255, 215, 0, 95)
            Case 162
                Return Color.FromArgb(255, 215, 0, 135)
            Case 163
                Return Color.FromArgb(255, 215, 0, 175)
            Case 164
                Return Color.FromArgb(255, 215, 0, 215)
            Case 165
                Return Color.FromArgb(255, 215, 0, 255)
            Case 166
                Return Color.FromArgb(255, 215, 95, 0)
            Case 167
                Return Color.FromArgb(255, 215, 95, 95)
            Case 168
                Return Color.FromArgb(255, 215, 95, 135)
            Case 169
                Return Color.FromArgb(255, 215, 95, 175)
            Case 170
                Return Color.FromArgb(255, 215, 95, 215)
            Case 171
                Return Color.FromArgb(255, 215, 95, 255)
            Case 172
                Return Color.FromArgb(255, 215, 135, 0)
            Case 173
                Return Color.FromArgb(255, 215, 135, 95)
            Case 174
                Return Color.FromArgb(255, 215, 135, 135)
            Case 175
                Return Color.FromArgb(255, 215, 135, 175)
            Case 176
                Return Color.FromArgb(255, 215, 135, 215)
            Case 177
                Return Color.FromArgb(255, 215, 135, 255)
            Case 178
                Return Color.FromArgb(255, 215, 175, 0)
            Case 179
                Return Color.FromArgb(255, 215, 175, 95)
            Case 180
                Return Color.FromArgb(255, 215, 175, 135)
            Case 181
                Return Color.FromArgb(255, 215, 175, 175)
            Case 182
                Return Color.FromArgb(255, 215, 175, 215)
            Case 183
                Return Color.FromArgb(255, 215, 175, 255)
            Case 184
                Return Color.FromArgb(255, 215, 215, 0)
            Case 185
                Return Color.FromArgb(255, 215, 215, 95)
            Case 186
                Return Color.FromArgb(255, 215, 215, 135)
            Case 187
                Return Color.FromArgb(255, 215, 215, 175)
            Case 188
                Return Color.FromArgb(255, 215, 215, 215)
            Case 189
                Return Color.FromArgb(255, 215, 215, 255)
            Case 190
                Return Color.FromArgb(255, 215, 255, 0)
            Case 191
                Return Color.FromArgb(255, 215, 255, 95)
            Case 192
                Return Color.FromArgb(255, 215, 255, 135)
            Case 193
                Return Color.FromArgb(255, 215, 255, 175)
            Case 194
                Return Color.FromArgb(255, 215, 255, 215)
            Case 195
                Return Color.FromArgb(255, 215, 255, 255)
            Case 196
                Return Color.FromArgb(255, 255, 0, 0)
            Case 197
                Return Color.FromArgb(255, 255, 0, 95)
            Case 198
                Return Color.FromArgb(255, 255, 0, 135)
            Case 199
                Return Color.FromArgb(255, 255, 0, 175)
            Case 200
                Return Color.FromArgb(255, 255, 0, 215)
            Case 201
                Return Color.FromArgb(255, 255, 0, 255)
            Case 202
                Return Color.FromArgb(255, 255, 95, 0)
            Case 203
                Return Color.FromArgb(255, 255, 95, 95)
            Case 204
                Return Color.FromArgb(255, 255, 95, 135)
            Case 205
                Return Color.FromArgb(255, 255, 95, 175)
            Case 206
                Return Color.FromArgb(255, 255, 95, 215)
            Case 207
                Return Color.FromArgb(255, 255, 95, 255)
            Case 208
                Return Color.FromArgb(255, 255, 135, 0)
            Case 209
                Return Color.FromArgb(255, 255, 135, 95)
            Case 210
                Return Color.FromArgb(255, 255, 135, 135)
            Case 211
                Return Color.FromArgb(255, 255, 135, 175)
            Case 212
                Return Color.FromArgb(255, 255, 135, 215)
            Case 213
                Return Color.FromArgb(255, 255, 135, 255)
            Case 214
                Return Color.FromArgb(255, 255, 175, 0)
            Case 215
                Return Color.FromArgb(255, 255, 175, 95)
            Case 216
                Return Color.FromArgb(255, 255, 175, 135)
            Case 217
                Return Color.FromArgb(255, 255, 175, 175)
            Case 218
                Return Color.FromArgb(255, 255, 175, 215)
            Case 219
                Return Color.FromArgb(255, 255, 175, 255)
            Case 220
                Return Color.FromArgb(255, 255, 215, 0)
            Case 221
                Return Color.FromArgb(255, 255, 215, 95)
            Case 222
                Return Color.FromArgb(255, 255, 215, 135)
            Case 223
                Return Color.FromArgb(255, 255, 215, 175)
            Case 224
                Return Color.FromArgb(255, 255, 215, 215)
            Case 225
                Return Color.FromArgb(255, 255, 215, 255)
            Case 226
                Return Color.FromArgb(255, 255, 255, 0)
            Case 227
                Return Color.FromArgb(255, 255, 255, 95)
            Case 228
                Return Color.FromArgb(255, 255, 255, 135)
            Case 229
                Return Color.FromArgb(255, 255, 255, 175)
            Case 230
                Return Color.FromArgb(255, 255, 255, 215)
            Case 231
                Return Color.FromArgb(255, 255, 255, 255)
            Case 232
                Return Color.FromArgb(255, 8, 8, 8)
            Case 233
                Return Color.FromArgb(255, 18, 18, 18)
            Case 234
                Return Color.FromArgb(255, 28, 28, 28)
            Case 235
                Return Color.FromArgb(255, 38, 38, 38)
            Case 236
                Return Color.FromArgb(255, 48, 48, 48)
            Case 237
                Return Color.FromArgb(255, 58, 58, 58)
            Case 238
                Return Color.FromArgb(255, 68, 68, 68)
            Case 239
                Return Color.FromArgb(255, 78, 78, 78)
            Case 240
                Return Color.FromArgb(255, 88, 88, 88)
            Case 241
                Return Color.FromArgb(255, 98, 98, 98)
            Case 242
                Return Color.FromArgb(255, 108, 108, 108)
            Case 243
                Return Color.FromArgb(255, 118, 118, 118)
            Case 244
                Return Color.FromArgb(255, 128, 128, 128)
            Case 245
                Return Color.FromArgb(255, 138, 138, 138)
            Case 246
                Return Color.FromArgb(255, 148, 148, 148)
            Case 247
                Return Color.FromArgb(255, 158, 158, 158)
            Case 248
                Return Color.FromArgb(255, 168, 168, 168)
            Case 249
                Return Color.FromArgb(255, 178, 178, 178)
            Case 250
                Return Color.FromArgb(255, 188, 188, 188)
            Case 251
                Return Color.FromArgb(255, 198, 198, 198)
            Case 252
                Return Color.FromArgb(255, 208, 208, 208)
            Case 253
                Return Color.FromArgb(255, 218, 218, 218)
            Case 254
                Return Color.FromArgb(255, 228, 228, 228)
            Case 255
                Return Color.FromArgb(255, 238, 238, 238)

        End Select
    End Function
#End Region
#Region "IAC handling"
    Public Sub IACDo(ByVal buffer As Byte)
        dolog("IAC DO " + CStr(buffer))
        Dim response() As Byte
        Select Case buffer
            Case IAC_ECHO
                dolog("Sending IAC WILL ECHO")
                response = {IAC_COMMAND, IAC_WILL, IAC_ECHO}
                sendIAC(response)
            Case IAC_SGA
                dolog("Sending IAC WILL SGA")
                response = {IAC_COMMAND, IAC_WILL, IAC_SGA}
                sendIAC(response)
            Case IAC_STATUS
                dolog("Do STATUS")
                'How do we do this?
            Case IAC_TMRK
                dolog("Do TMRK")
            Case IAC_TERM
                response = {IAC_COMMAND, IAC_WILL, IAC_TERM}
                sendIAC(response)
                dolog("Sending IAC WILL TERM")
            Case IAC_EOR
                dolog("Sending IAC WONT EOR")
                response = {IAC_COMMAND, IAC_WONT, IAC_EOR}
                sendIAC(response)

            Case IAC_NAWS
                dolog("Do NAWS!")
                response = {IAC_COMMAND, IAC_WILL, IAC_NAWS}
                dolog("Sending IAC WILL NAWS")
                sendIAC(response)
            Case IAC_TSPEED
                dolog("Do TSPEED")
            Case IAC_FLOW
                dolog("Do FLOW")
            Case IAC_LINE
                dolog("Do Line!")
                response = {IAC_COMMAND, IAC_WILL, IAC_LINE}
                sendIAC(response)
                dolog("Sending IAC WILL LINE")
            Case IAC_XDISP
                dolog("Do XDISP")
                response = {IAC_COMMAND, IAC_WONT, IAC_XDISP}
                sendIAC(response)
            Case IAC_CHARSET
                dolog("Sending IAC WILL CHARSET")
                response = {IAC_COMMAND, IAC_WILL, IAC_CHARSET}
                sendIAC(response)
            Case IAC_STARTTLS
                dolog("Server wants to start TLS, sending WONT STARTTLS")
                response = {IAC_COMMAND, IAC_WONT, IAC_STARTTLS}
                sendIAC(response)
        End Select

    End Sub
    Public Sub NegotiateNAWS()
        Dim response() As Byte
        Dim height As Int16
        Dim width As Int16

        height = worldoutput.Height / worldoutput.Font.Size
        If height > 254 Then
            height = 254

        End If
        dolog("Worldoutput width: " + CStr(worldoutput.Width))
        width = CInt(worldoutput.Width) / 9

        response = {IAC_COMMAND, IAC_SB, IAC_NAWS, CByte(0), CByte(width), CByte(0), CByte(height), IAC_COMMAND, IAC_SE}
        dolog("Sending NAWS height " + CStr(height) + " width " + CStr(width) + ".")
        dolog("Byte for height:" + CStr(CByte(height)))
        dolog("Byte for width:" + CStr(CByte(width)))

        sendIAC(response)
    End Sub
    Public Sub sendIAC(ByVal buffer() As Byte)
        Try
            WorldStream.Write(buffer, 0, buffer.Length)
            WorldStream.Flush()
            dolog("Sent some IAC data straight to the buffer")
        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        End Try
    End Sub
    Public Sub TelnetIAC(ByVal buffer() As Byte, ByVal startpos As Long)
        Dim bLength As Long
        Dim IACCommand As Byte
        Dim i As Long
        Dim tempbuffer() As Byte
        bLength = UBound(buffer)
        For i = 0 To bLength - 1
            If (buffer(i) = CByte(255)) Then
                ' Found the IAC
                IACCommand = buffer(i + 1)
                Select Case IACCommand
                    Case IAC_COMMAND
                        'We got a literal byte 255, so go back to outputting.
                        dolog("Found another IAC immediately after the first, this shouldn't happen as its supposed to be caught earlier.!")
                    Case IAC_DO
                        dolog("Got IAC DO command")
                        IACDo(buffer(i + 2))
                    Case IAC_DONT
                        dolog("Got IAC DON'T command:" + CStr(buffer(i + 2)))
                    Case IAC_WILL
                        dolog("Got IAC WILL command")
                        IACWill(buffer, i)
                    Case IAC_WONT
                        dolog("Got IAC WON'T command")
                    Case IAC_SB
                        dolog("Got IAC SB command")
                        IACDoSB(buffer, i)
                    Case IAC_GA
                        dolog("Got IAC Go ahead")
                    Case IAC_ERASELINE
                        dolog("Got IAC Erase Line")
                    Case IAC_ERASECHAR
                        dolog("Got IAC erase character")
                    Case IAC_AYT
                        dolog("Got IAC Are You There")
                    Case IAC_ABORT
                        dolog("Got IAC Abort Output")
                    Case IAC_INTERRUPT
                        dolog("Got IAC Interrupt Process")
                    Case IAC_BREAK
                        dolog("Got IAC Break")
                    Case IAC_DATA
                        dolog("Got IAC Data Mark")
                    Case IAC_NOP
                        dolog("Got IAC NOP")
                    Case IAC_SE
                        dolog("Got IAC SE")
                    Case Else
                        dolog("Doesn't seem to be an IAC sequence, passing back to outputhandler.")
                        ReDim tempbuffer(UBound(buffer) - i)
                        For l = (i + 1) To (UBound(buffer) - 1)
                            tempbuffer((l - (i + 1))) = buffer(l)
                        Next
                        updateoutput(tempbuffer)
                        Exit Sub
                End Select

            End If
        Next
    End Sub
    Public Sub IACWill(ByVal buffer() As Byte, ByVal startpoint As Long)
        Dim IACCommand As Byte
        Dim IACType As Byte
        Dim response() As Byte
        ' We already know where in the buffer our IAC command is, so parse from there
        IACCommand = buffer(startpoint + 1)
        IACType = buffer(startpoint + 2)
        Select Case IACType
            Case IAC_NAWS
                dolog("Server says WILL NAWS, why?")
            Case IAC_MSSP
                dolog("Server suggests MSSP, sending DO MSSP")
                response = {IAC_COMMAND, IAC_DO, IAC_MSSP}
                sendIAC(response)
            Case IAC_MSP
                dolog("Server suggests MSP, sending DO MSP")
                response = {IAC_COMMAND, IAC_DO, IAC_MSP}
                sendIAC(response)
            Case IAC_CHARSET
                dolog("Server suggests CHARSET")
                response = {IAC_COMMAND, IAC_DO, IAC_CHARSET}
                sendIAC(response)
            Case IAC_IYFL
                dolog("Server suggests IYFL")
                response = {IAC_COMMAND, IAC_DO, IAC_IYFL}
                sendIAC(response)
        End Select
    End Sub
    Public Sub IACDoSB(ByVal buffer() As Byte, ByVal startpoint As Long)
        Dim blength As Long
        Dim IACSBCommand As Byte
        Dim response() As Byte
        Dim temp() As Byte
        Dim mychar() As Byte
        Dim mychar2() As Byte
        Dim MSSP_var As String = ""
        Dim MSSP_val As String = ""
        dolog("Entered IACDoSB. My current buffer:")

        blength = UBound(buffer)
        IACSBCommand = buffer(startpoint + 2)
        dolog("IACSBCommand :" + CStr(IACSBCommand))


        Select Case IACSBCommand
            Case IAC_LINE
                dolog("Negotiating about LINEMODE")
                'Yes yes, we accept, go ahead.
                response = {IAC_COMMAND, IAC_SB, IAC_LINE, CByte(1), buffer(startpoint + 3), IAC_COMMAND, IAC_SE}
                sendIAC(response)
            Case IAC_NAWS
                dolog("Negotiating NAWS")
            Case IAC_TERM
                dolog("Negotiating TERM")
                For i = startpoint To blength
                    dolog("Got TERM byte: " + CStr(buffer(i)))
                    If (buffer(i) = CByte(1)) Then
                        Dim response2() As Byte
                        Dim termname() As Byte
                        Dim command() As Byte
                        termname = System.Text.Encoding.Default.GetBytes("OrangeClient-256color")
                        command = {IAC_COMMAND, IAC_SB, IAC_TERM, CByte(0), CByte(0)}
                        response2 = command
                        ReDim Preserve response2(UBound(command) + UBound(termname) + 2)
                        For j = 0 To UBound(termname)
                            response2(j + UBound(command)) = termname(j)
                        Next
                        response2(UBound(response2) - 1) = IAC_COMMAND
                        response2(UBound(response2)) = IAC_SE

                        dolog("Sending Term response " + System.Text.Encoding.Default.GetString(response2) + ", which is in bytes:")
                        For k = 0 To UBound(response2)
                            dolog("Byte:" + CStr(response2(k)))
                        Next
                        sendIAC(response2)
                        NegotiateNAWS()
                        ReDim temp(UBound(buffer) - i)
                        For l = (i + 1) To (UBound(buffer) - 1)
                            temp((l - (i + 1))) = buffer(l)
                        Next
                        'updateoutput(temp)
                        Exit For
                    End If
                Next
            Case IAC_IYFL
                dolog("Negotiating IYFL")
                For i = startpoint To blength
                    Select Case buffer(i)
                        Case CByte(1)
                            dolog("Got IYFL SEND message")

                    End Select
                Next
            Case IAC_MSSP
                dolog("Negotiating MSSP")
                mudinfo.Clear()

                For i = startpoint To blength
                    'dolog("Byte: " + CStr(buffer(i)))
                    Select Case buffer(i)
                        Case CByte(1)
                            'dolog("Got a MSSP_VAR")
                            'Read forward until we know what we got told
                            For j = i To blength
                                If (buffer(j) = CByte(2)) Then
                                    For k = j + 1 To blength
                                        If (buffer(k) = CByte(1)) Then
                                            mudinfo.Add(MSSP_var, MSSP_val)
                                            MSSP_var = Nothing
                                            MSSP_val = Nothing

                                            Exit For

                                        End If
                                        mychar2 = {buffer(k)}
                                        MSSP_val += System.Text.Encoding.UTF8.GetString(mychar2)

                                        'dolog("In inner readloop, byte: " + System.Text.Encoding.ASCII.GetString(mychar2) + ", value now " + MSSP_val)

                                    Next
                                    Exit For
                                End If
                                'dolog("char: " + CStr(buffer(j)))
                                mychar = {buffer(j)}
                                'dolog("In readloop, byte: " + System.Text.Encoding.ASCII.GetString(mychar) + ", value now " + MSSP_var)
                                MSSP_var += System.Text.Encoding.UTF8.GetString(mychar)
                            Next
                        Case CByte(2)
                            'dolog("Got a MSSP_VAL")
                        Case CByte(IAC_SE)
                            'dolog("Got IAC SE Byte")
                    End Select
                Next
                dolog("Done processing MSSP.")
                MainForm.ToolStripStatusLabel1.ToolTipText = "MU* Information from MSSP:" + vbCrLf
                MainForm.ToolStripStatusLabel1.AutoToolTip = True
                MainForm.ToolStripStatusLabel2.Text = "Send NAWS"

                For Each kvp As KeyValuePair(Of String, String) In mudinfo
                    dolog("Mu*info: " + kvp.Key + ":" + kvp.Value)
                    MainForm.ToolStripStatusLabel1.ToolTipText += kvp.Key + ": " + kvp.Value + vbCrLf
                    MainForm.ToolStripStatusLabel1.Text = "MSSP information available"
                    MainForm.ToolStripStatusLabel1.IsLink = True
                Next

            Case IAC_STARTTLS
                dolog("In STARTTLS")
            Case IAC_CHARSET
                Dim charsets() As String = {}
                Dim tempstr As String = ""
                Dim newchar() As Byte = {}
                Dim canutf8 As Boolean
                Dim mysep As Byte
                dolog("Entered CHARSET negotiation")
                'dolog("Buffer reads as: " + System.Text.Encoding.ASCII.GetString(buffer))
                'We know where the separator in the list is, it's the first byte after SB, so let's be smart and grab that rather than rely on it all being ;
                mysep = buffer(startpoint + 4)
                For i = (startpoint + 4) To blength
                    'dolog("Got CHARSET byte: " + CStr(buffer(i)))
                    If (buffer(i) = mysep) Then
                        dolog("Server offers charset " + tempstr + ".")
                        ReDim Preserve charsets(UBound(charsets) + 1)
                        charsets(UBound(charsets)) = tempstr
                        tempstr = ""

                    ElseIf (buffer(i) = CByte(255)) Then
                        'dolog("Got an IAC")
                        If (buffer(i + 1) = CByte(240)) Then
                            'dolog("Charset list complete, ")
                            For Each charset As String In charsets
                                If charset.Contains("UTF-8") Then
                                    dolog("Picking UTF-8 charset")
                                    canutf8 = True
                                End If
                            Next
                            If (canutf8 = True) Then
                                dolog("Enabling UTF8 mode!")
                                response = {IAC_COMMAND, IAC_SB, IAC_CHARSET, CByte(2), CByte(85), CByte(84), CByte(70), CByte(45), CByte(56), IAC_COMMAND, IAC_SE}
                                sendIAC(response)
                                useUTF8 = True
                                MainForm.ToolStripStatusLabel2.Text = "UTF8 mode"

                            Else
                                dolog("No charset we want, rejecting and resuming default parsing.")
                                response = {IAC_COMMAND, IAC_SB, IAC_CHARSET, CByte(3), IAC_COMMAND, IAC_SE}
                                sendIAC(response)
                                useUTF8 = False
                                MainForm.ToolStripStatusLabel2.Text = "ASCII mode"
                            End If
                            ReDim temp(UBound(buffer) - i)
                            For l = (i + 1) To (UBound(buffer) - 1)
                                temp((l - (i + 1))) = buffer(l)
                            Next
                            updateoutput(temp)
                        End If
                    ElseIf (buffer(i) = CByte(1)) Then
                        dolog("Got CHARSET REQUEST")
                    Else
                        newchar = {buffer(i)}
                        'dolog("Push to tempstr: " + System.Text.Encoding.ASCII.GetString(newchar))
                        tempstr += System.Text.Encoding.ASCII.GetString(newchar)

                    End If
                    'If (buffer(i) = CByte(1)) Then
                    '    Dim response2() As Byte
                    '    Dim termname() As Byte
                    '    Dim command() As Byte
                    '    termname = System.Text.Encoding.Default.GetBytes("OrangeClient")
                    '    command = {IAC_COMMAND, IAC_SB, IAC_TERM, CByte(0), CByte(0)}
                    '    response2 = command
                    '    ReDim Preserve response2(UBound(command) + UBound(termname) + 2)
                    '    For j = 0 To UBound(termname)
                    '        response2(j + UBound(command)) = termname(j)
                    '    Next
                    '    response2(UBound(response2) - 1) = IAC_COMMAND
                    '    response2(UBound(response2)) = IAC_SE

                    '    dolog("Sending Term response " + System.Text.Encoding.Default.GetString(response2) + ", which is in bytes:")
                    '    For k = 0 To UBound(response2)
                    '        dolog("Byte:" + CStr(response2(k)))
                    '    Next
                    '    sendIAC(response2)
                    '    NegotiateNAWS()
                    '    Exit For
                    'End If
                Next
        End Select

    End Sub
#End Region



End Class

